#ifndef _STDARG_H
#define _STDARG_H

typedef char *va_list;

/*
 * TYPE类型的字节大小，按照 int 类型（对于此处是4字节）向上对齐
 *      例如:   sizeof(TYPE) = 3, sizeof(int) = 4, 那么 __va_rounded_size(TYPE) = 4
 *              sizeof(TYPE) = 5, sizeof(int) = 4, 那么 __va_rounded_size(TYPE) = 8
 * 这种向上取整的方式之所有行之有效，是因为入栈的参数遵循如下原则：
 *      当函数 没有原型声明 或为 可变参数函数（如printf）时
 *      C标准要求较小的整数类型（如char、short）被提升为int（4字节），
 *      浮点类型（如float）被提升为double（8字节）
 *      因此，这种情况下，入栈的参数，即使是 char ，也会按照 int 大小进行入栈
 */
#define __va_rounded_size(TYPE) \
    (((sizeof(TYPE) + sizeof(int) - 1) / sizeof(int)) * sizeof(int))

/* 获取LASTARG参数的地址，并跳过LASTARG参数的长度。实际就是取LASTARG后一个参数的地址 */
#define va_start(AP, LASTARG)   \
    (AP = ((char *)&(LASTARG) + __va_rounded_size(LASTARG)))

void va_end(va_list);   /* 在gnulib中定义 */
#define va_end(AP)

/* 使用了括号表达式，返回的是括号中的最后表达式 */
/* 让 AP 移动到下一个参数的地址处，但是按照TYPE类型返回AP移动之前地址的值 */
#define va_arg(AP, TYPE)    \
    (AP += __va_rounded_size(TYPE),    \
    *((TYPE *)(AP - __va_rounded_size(TYPE))))


#endif /* _STDARG_H */